package com.metaverse.backend.service;

import com.metaverse.backend.config.SysConstants;
import com.metaverse.backend.domain.*;
import com.metaverse.backend.enums.*;
import com.metaverse.backend.exception.BusinessException;

import com.metaverse.backend.repo.*;
import com.metaverse.backend.security.Authority;
import com.metaverse.backend.security.JwtTokenUtil;
import com.metaverse.backend.security.JwtUserFactory;
import com.metaverse.backend.service.loginLog.LoginLogService;

import com.metaverse.backend.dto.PageQuery;
import com.metaverse.backend.dto.UserRegister;
import com.metaverse.backend.utils.JpaUtils;
import com.metaverse.backend.utils.ObjUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.domain.Page;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.Predicate;
import javax.transaction.Transactional;
import java.time.LocalDateTime;
import java.util.*;

@Service
@Slf4j
@AllArgsConstructor
public class UserService {
    private UserRepo userRepo;
    private JwtTokenUtil jwtTokenUtil;
    private final LoginLogService loginLogService;

    private final SysConfigService sysConfigService;

    public Page<User> all(PageQuery pageQuery) {
        Specification<User> specification = JpaUtils.toSpecification(pageQuery, User.class);

        specification = specification.and((Specification<User>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> and = new ArrayList<>();
            and.add(criteriaBuilder.equal(root.get("del"), false));

//            if (!pageQuery.getQuery().containsKey("admin")) {
//                and.add(criteriaBuilder.equal(root.get("admin"), false));
//            }

            if (pageQuery.getQuery().containsKey("hasRole")) {
                String roleName = (String) pageQuery.getQuery().get("hasRole");
                and.add(criteriaBuilder.isMember(Authority.get(AuthorityName.valueOf(roleName)), root.get("authorities")));
            }
            return criteriaBuilder.and(and.toArray(new Predicate[0]));
        });
        return userRepo.findAll(specification, JpaUtils.toPageRequest(pageQuery));
    }

    /**
     * 创建账户
     *
     * @param userRegister
     * @return
     */
    @Transactional
    public User create(UserRegister userRegister) {

        User user =  null;
        if(userRegister.getOpenid() != null){
            user = userRepo.findByOpenid(userRegister.getOpenid());
        }


        if (user == null) {
            user = new User();
            BeanUtils.copyProperties(userRegister, user);
            String password = user.getPassword();
            if(StringUtils.isNotEmpty(password)){
                user.setPassword(new BCryptPasswordEncoder().encode(password));
            }

            //自动生成用户名
            String username = generateUserName();
            user.setUsername(username);
            //密码加密处理
            userRepo.save(user);
        }
        return user;
    }



    /**
     * 更新用户
     * @param fromUser
     * @return
     */
    @Transactional
    public User addOrUpdate(User fromUser) {
        User orig;
        if(fromUser.getId() != null){
            orig = userRepo.findById(fromUser.getId()).orElseThrow(new BusinessException("用户无记录"));
            ObjUtils.merge(orig, fromUser);
        }else{
            orig = fromUser;

        }

        if(fromUser.getPassword() != null){
            //设置了密码，需要重新加密
            orig.setPassword(new BCryptPasswordEncoder().encode(orig.getPassword()));
        }



        userRepo.save(orig);
        return orig;
    }




    /**
     * 是否存在openid
     * @param openid
     * @return
     */
    public boolean existOpenid(String openid){
        return userRepo.findByOpenid(openid) != null;
    }

    /**
     * 登录
     * @param openid
     * @return
     */
    public User login(String openid, LoginType loginType) {
        User user = null;
        try {
             user =  userRepo.findByOpenid(openid);
            if(user.getStatus() != UserStatus.NORMAL){
                throw new BusinessException("账号状态不正确[" + user.getStatus().getDescription() + "]");
            }
            return user;
        }catch (BusinessException e){
            throw e;
        }finally {
            LoginLog loginLog = LoginLog.builder()
                    .loginSuccess(true)
                    .loginTime(LocalDateTime.now())
                    .userId(user == null ? null : user.getId())
                    .loginType(loginType)
                    .build();
            loginLogService.pushLoginLog(loginLog);
        }
    }


    /**
     * 修改密码
     * @param userId
     * @param password
     * @return
     */
    @Transactional
    public String setPassword(Long userId, String password) {
        User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
        user.setPassword(new BCryptPasswordEncoder().encode(password));
        user = userRepo.save(user);
        return jwtTokenUtil.generateToken(JwtUserFactory.create(user));
    }



    /**
     * 产生用户名称
     * @return
     */
    public String generateUserName(){
        String memberPrefix  = sysConfigService.getStringDefault(SysConstants.MEMBER_PREFIX);
        String randomName = RandomStringUtils.randomAlphabetic(10);
        return memberPrefix + randomName;
    }


    public User updateData(User user){
        return userRepo.save(user);
    }

    public void deleteById(Long id){
         userRepo.deleteById(id);
    }





}
